
#include "bsp/bsp.h"
#include "adc.h"
#include "gpio.h"

ADC_HandleTypeDef hadc1;
ADC_HandleTypeDef hadc2;
ADC_HandleTypeDef hadc3;
DMA_HandleTypeDef hdma_adc1;


static void Error_Handler(void){}
/* ADC1 init function */
void MX_ADC1_Init(void)
{	
	ADC_ChannelConfTypeDef sConfig = {0};
		
	/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
	*/
	hadc1.Instance = ADC1;
	hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
	hadc1.Init.Resolution = ADC_RESOLUTION_12B;
	hadc1.Init.ScanConvMode = ENABLE;
	hadc1.Init.ContinuousConvMode = ENABLE;
	hadc1.Init.DiscontinuousConvMode = DISABLE;
	hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
	hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
	hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
	hadc1.Init.NbrOfConversion = 3;
	hadc1.Init.DMAContinuousRequests = ENABLE;
	hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;
	if (HAL_ADC_Init(&hadc1) != HAL_OK)
	{
	  	Error_Handler();
	}
	
	/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
	*/
	sConfig.Channel = VBUS_ADC_SAMPLE_CHAN;
	sConfig.Rank = 1;
	sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
	if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
	{
	  	Error_Handler();
	}
	
	/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
	*/
	sConfig.Channel = MOTOR_TEMP_ADC_CHAN;
	sConfig.Rank = 2;
	if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
	{
	  	Error_Handler();
	}
	
	/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
	*/
	sConfig.Channel = AUX_TEMP_ADC_CHAN;
	sConfig.Rank = 3;
	if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
	{
	  	Error_Handler();
	}
}
/* ADC2 init function */
void MX_ADC2_Init(void)
{
	ADC_ChannelConfTypeDef sConfig = {0};
	ADC_InjectionConfTypeDef sConfigInjected = {0};
		
	/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
	*/
	hadc2.Instance = ADC2;
	hadc2.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
	hadc2.Init.Resolution = ADC_RESOLUTION_12B;
	hadc2.Init.ScanConvMode = ENABLE;
	hadc2.Init.ContinuousConvMode = DISABLE;
	hadc2.Init.DiscontinuousConvMode = DISABLE;
	hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
	hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;
	hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
	hadc2.Init.NbrOfConversion = 1;
	hadc2.Init.DMAContinuousRequests = DISABLE;
	hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
	if (HAL_ADC_Init(&hadc2) != HAL_OK)
	{
	  	Error_Handler();
	}
	
	/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
	*/
	sConfig.Channel = IU_ADC_SAMPLE_CHAN;
	sConfig.Rank = 1;
	sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
	if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
	{
	  	Error_Handler();
	}
	
	/** Configures for the selected ADC injected channel its corresponding rank in the sequencer and its sample time
	*/
	sConfigInjected.InjectedChannel = IU_ADC_SAMPLE_CHAN;
	sConfigInjected.InjectedRank = 1;
#ifndef CONFIG_ADC2_3_IU_IV
	sConfigInjected.InjectedNbrOfConversion = 2;
#else
	sConfigInjected.InjectedNbrOfConversion = 1;
#endif
	sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_3CYCLES;
	sConfigInjected.ExternalTrigInjecConvEdge = ADC_EXTERNALTRIGINJECCONVEDGE_RISING;
	sConfigInjected.ExternalTrigInjecConv = ADC_EXTERNALTRIGINJECCONV_T1_TRGO;
	sConfigInjected.AutoInjectedConv = DISABLE;
	sConfigInjected.InjectedDiscontinuousConvMode = DISABLE;
	sConfigInjected.InjectedOffset = 0;
	if (HAL_ADCEx_InjectedConfigChannel(&hadc2, &sConfigInjected) != HAL_OK)
	{
	  	Error_Handler();
	}
#ifndef CONFIG_ADC2_3_IU_IV
	sConfigInjected.InjectedChannel = IV_ADC_SAMPLE_CHAN;
	sConfigInjected.InjectedRank = 2;
	if (HAL_ADCEx_InjectedConfigChannel(&hadc2, &sConfigInjected) != HAL_OK)
	{
	  	Error_Handler();
	}
#endif
	__HAL_ADC_DISABLE_IT(&hadc2, ADC_IT_JEOC);
	__HAL_ADC_CLEAR_FLAG(&hadc2, ADC_FLAG_JEOC);
}
/* ADC3 init function */
void MX_ADC3_Init(void)
{
	ADC_ChannelConfTypeDef sConfig = {0};
	ADC_InjectionConfTypeDef sConfigInjected = {0};
	
	/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
	*/
	hadc3.Instance = ADC3;
	hadc3.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
	hadc3.Init.Resolution = ADC_RESOLUTION_12B;
	hadc3.Init.ScanConvMode = ENABLE;
	hadc3.Init.ContinuousConvMode = DISABLE;
	hadc3.Init.DiscontinuousConvMode = DISABLE;
	hadc3.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
	hadc3.Init.ExternalTrigConv = ADC_SOFTWARE_START;
	hadc3.Init.DataAlign = ADC_DATAALIGN_RIGHT;
	hadc3.Init.NbrOfConversion = 1;
	hadc3.Init.DMAContinuousRequests = DISABLE;
	hadc3.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
	if (HAL_ADC_Init(&hadc3) != HAL_OK)
	{
	  	Error_Handler();
	}
	
	/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
	*/
	sConfig.Channel = IV_ADC_SAMPLE_CHAN;
	sConfig.Rank = 1;
	sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
	if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK)
	{
	  	Error_Handler();
	}
	
	/** Configures for the selected ADC injected channel its corresponding rank in the sequencer and its sample time
	*/
	sConfigInjected.InjectedChannel = IV_ADC_SAMPLE_CHAN;
	sConfigInjected.InjectedRank = 1;
	sConfigInjected.InjectedNbrOfConversion = 1;
	sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_3CYCLES;
	sConfigInjected.ExternalTrigInjecConvEdge = ADC_EXTERNALTRIGINJECCONVEDGE_RISING;
	sConfigInjected.ExternalTrigInjecConv = ADC_EXTERNALTRIGINJECCONV_T1_TRGO;
	sConfigInjected.AutoInjectedConv = DISABLE;
	sConfigInjected.InjectedDiscontinuousConvMode = DISABLE;
	sConfigInjected.InjectedOffset = 0;
	if (HAL_ADCEx_InjectedConfigChannel(&hadc3, &sConfigInjected) != HAL_OK)
	{
	  	Error_Handler();
	}
	__HAL_ADC_DISABLE_IT(&hadc3, ADC_IT_JEOC);
	__HAL_ADC_CLEAR_FLAG(&hadc3, ADC_FLAG_JEOC);
}

void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
  	GPIO_InitTypeDef GPIO_InitStruct = {0};
  	if(hadc->Instance==ADC1)
  	{
    	__HAL_RCC_ADC1_CLK_ENABLE();

    	__HAL_RCC_GPIOA_CLK_ENABLE();
    	__HAL_RCC_GPIOC_CLK_ENABLE();
    	/**ADC1 GPIO Configuration
    	PA5     ------> ADC1_IN5
    	PA6     ------> ADC1_IN6
    	PC5     ------> ADC1_IN15
    	*/
    	gpio_analog_init(VBUS_ADC_PIO);
		gpio_analog_init(MOTOR_TEMP_ADC_PIO);
		gpio_analog_init(AUX_TEMP_ADC_PIO);
    	/* ADC1 DMA Init */
    	/* ADC1 Init */
    	hdma_adc1.Instance = DMA2_Stream0;
    	hdma_adc1.Init.Channel = DMA_CHANNEL_0;
    	hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
    	hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
    	hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
    	hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
    	hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    	hdma_adc1.Init.Mode = DMA_CIRCULAR;
    	hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;
    	hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
		
    	if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
    	{
      		Error_Handler();
    	}

    	__HAL_LINKDMA(hadc,DMA_Handle,hdma_adc1);
  	} else if(hadc->Instance==ADC2) {
    	__HAL_RCC_ADC2_CLK_ENABLE();

    	__HAL_RCC_GPIOC_CLK_ENABLE();
    	/**ADC2 GPIO Configuration
    	PC1     ------> ADC2_IN11
    	*/
    	gpio_analog_init(IU_ADC_PIO);
#ifndef CONFIG_ADC2_3_IU_IV
		gpio_analog_init(IV_ADC_PIO);
#endif
  	} else if(hadc->Instance==ADC3) {
    	__HAL_RCC_ADC3_CLK_ENABLE();

    	__HAL_RCC_GPIOC_CLK_ENABLE();
    	/**ADC3 GPIO Configuration
    	PC0     ------> ADC3_IN10
    	*/
		gpio_analog_init(IV_ADC_PIO);
  	}
}

/**
* @brief ADC MSP De-Initialization
* This function freeze the hardware resources used in this example
* @param hadc: ADC handle pointer
* @retval None
*/
void HAL_ADC_MspDeInit(ADC_HandleTypeDef* hadc)
{
  	if(hadc->Instance==ADC1)
  	{
    	__HAL_RCC_ADC1_CLK_DISABLE();

    	/**ADC1 GPIO Configuration
    	PA5     ------> ADC1_IN5
    	PA6     ------> ADC1_IN6
    	PC5     ------> ADC1_IN15
    	*/
		gpio_deinit(VBUS_ADC_PIO);
		gpio_deinit(MOTOR_TEMP_ADC_PIO);
		gpio_deinit(AUX_TEMP_ADC_PIO);

    	HAL_DMA_DeInit(hadc->DMA_Handle);
  	} else if(hadc->Instance==ADC2) {
    	__HAL_RCC_ADC2_CLK_DISABLE();

    	/**ADC2 GPIO Configuration
    	PC1     ------> ADC2_IN11
    	*/
    	gpio_deinit(IU_ADC_PIO);
  	} else if(hadc->Instance==ADC3) {
    	__HAL_RCC_ADC3_CLK_DISABLE();

    	/**ADC3 GPIO Configuration
    	PC0     ------> ADC3_IN10
    	*/
    	gpio_deinit(IV_ADC_PIO);
  	}
}

static u16 dma_buffer[3];
void adc_init(void) {
	MX_ADC1_Init();
	MX_ADC2_Init();
#ifdef CONFIG_ADC2_3_IU_IV
	MX_ADC3_Init();
#endif
	HAL_NVIC_SetPriority(ADC_IRQn, ADC_IRQ_PRIORITY, 0);
	HAL_NVIC_EnableIRQ(ADC_IRQn);
	__HAL_ADC_StopConversionExtTrig(&hadc2);
#ifdef CONFIG_ADC2_3_IU_IV
	__HAL_ADC_StopConversionExtTrig(&hadc3);
#endif
	__HAL_ADC_ENABLE(&hadc1);
	__HAL_ADC_ENABLE(&hadc2);
#ifdef CONFIG_ADC2_3_IU_IV
	__HAL_ADC_ENABLE(&hadc3);
#endif
	cpu_udelay(1000);
	HAL_DMA_Start(&hdma_adc1, (u32)&(hadc1.Instance->DR), (u32)dma_buffer, 3);
	__HAL_ADC_ENABLE_DMA(&hadc1);
	__HAL_ADC_START_SW(&hadc1);
}

void adc_start_convert(void) {
	__disable_irq();
	__HAL_ADC_CLEAR_FLAG(&hadc2, ADC_FLAG_JEOC);
	__HAL_ADC_StartConversionExtTrig(&hadc2, ADC_EXTERNALTRIGINJECCONVEDGE_RISING);
	__HAL_ADC_ENABLE_IT(&hadc2, ADC_IT_JEOC);
	__HAL_ADC_CLEAR_FLAG(&hadc2, ADC_FLAG_JEOC);
#ifdef CONFIG_ADC2_3_IU_IV
	__HAL_ADC_CLEAR_FLAG(&hadc3, ADC_FLAG_JEOC);
	__HAL_ADC_StartConversionExtTrig(&hadc3, ADC_EXTERNALTRIGINJECCONVEDGE_RISING);
	__HAL_ADC_ENABLE_IT(&hadc3, ADC_IT_JEOC);
	__HAL_ADC_CLEAR_FLAG(&hadc3, ADC_FLAG_JEOC);
#endif
	__enable_irq();
}

void adc_stop_convert(void) {
	__disable_irq();
	__HAL_ADC_StopConversionExtTrig(&hadc2);
	__HAL_ADC_DISABLE_IT(&hadc2, ADC_IT_JEOC);
	__HAL_ADC_CLEAR_FLAG(&hadc2, ADC_FLAG_JEOC);
#ifdef CONFIG_ADC2_3_IU_IV
	__HAL_ADC_StopConversionExtTrig(&hadc3);
	__HAL_ADC_DISABLE_IT(&hadc3, ADC_IT_JEOC);
	__HAL_ADC_CLEAR_FLAG(&hadc3, ADC_FLAG_JEOC);
#endif
	__enable_irq();
}

void adc_get_phase_curr_value(uint8_t chan, int16_t *adc1, int16_t *adc2) {
    *adc1 = (int16_t)hadc2.Instance->JDR1;
#ifdef CONFIG_ADC2_3_IU_IV
	*adc2 = (int16_t)hadc3.Instance->JDR1;
#else
    *adc2 = (int16_t)hadc2.Instance->JDR2;
#endif
}

u16 adc_get_dc_voltage_value(void) {
	return dma_buffer[0];
}

u16 adc_get_mot_temp_value(void) {
	return dma_buffer[1];
}

u16 adc_get_aux_temp_value(void) {
	return dma_buffer[2];
}


